package com.hotel.core.utils;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class FTPUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(FTPUtil.class);
    private static final String UTF_8 = "UTF-8";
    private static final String ROOT = "/";
    private static final int CONNECT_TIMEOUT = 30000;
    private FTPClient ftpClient;
    private String ftpUrl;
    private int ftpPort;
    private String userName;
    private String passWord;
    private String charset;
    private String defaultWorkingDirectory;
    private int connectTimeout;

    public FTPUtil(String ftpUrl, int ftpPort, String userName, String passWord) {
        ftpClient = new FTPClient();
        this.ftpUrl = ftpUrl;
        this.ftpPort = ftpPort;
        this.userName = userName;
        this.passWord = passWord;
    }

    /**
     * 连接到FTP服务器
     *
     * @param hostname 主机名
     * @param port     端口
     * @param username 用户名
     * @param password 密码
     * @return 是否连接成功
     * @throws java.io.IOException
     */
    public boolean connect() throws IOException {
        return connect(this.ftpUrl, this.ftpPort, this.userName, this.passWord);
    }

    public boolean connect(String ftpUrl, int ftpPort, String userName,
                           String passWord) throws IOException {
        String charset = this.charset;
        if (StringUtils.isBlank(charset)) {
            charset = UTF_8;
        }
        if (connectTimeout == 0) {
            connectTimeout = CONNECT_TIMEOUT;
        }
        return connect(this.ftpUrl, this.ftpPort, this.userName, this.passWord,
                charset, connectTimeout);
    }

    private boolean connect(String ftpUrl, int ftpPort, String userName,
                            String passWord, String charset, int connectTimeout) throws IOException {
        ftpClient.connect(ftpUrl, ftpPort);
        ftpClient.setConnectTimeout(connectTimeout);
        ftpClient.setControlEncoding(charset);
        if (FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
            if (ftpClient.login(userName, passWord)) {
                return true;
            }
        }
        disconnect();
        return false;
    }

    /**
     * 断开与远程服务器的连接
     *
     * @throws java.io.IOException
     */
    public void disconnect() throws IOException {
        if (ftpClient != null && ftpClient.isConnected()) {
            ftpClient.disconnect();
        }
    }

    public void setControlEncoding(String charset) {
        this.charset = charset;
    }

    public void setDefaultWorkingDirectory(String workingDirectory) {
        this.defaultWorkingDirectory = workingDirectory;
    }

    public void setConnectTimeout(int connectTimeout) {
        this.connectTimeout = connectTimeout;
    }

    public String getFtpUrl() {
        return ftpUrl;
    }

    public void setFtpUrl(String ftpUrl) {
        this.ftpUrl = ftpUrl;
    }

    public int getFtpPort() {
        return ftpPort;
    }

    public void setFtpPort(int ftpPort) {
        this.ftpPort = ftpPort;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    public String getCharset() {
        return charset;
    }

    public void setCharset(String charset) {
        this.charset = charset;
    }

    public String getDefaultWorkingDirectory() {
        return defaultWorkingDirectory;
    }

    public int getConnectTimeout() {
        return connectTimeout;
    }

    /**
     * 删除文件
     *
     * @param fileName 要删除的服务端文件 如：000/000.txt
     * @return
     */
    public boolean deleteFile(String fileName) {
        try {
            return ftpClient.deleteFile(fileName);
        } catch (IOException e) {
            LOGGER.error("[FTP工具类]删除服务端文件异常", e);
            return false;
        }
    }

    /**
     * 获得FTP服务器目录下得文件列表
     *
     * @param path FTP服务器目录 如：000 根目录直接 "/"
     * @return
     */
    public List<String> getFileList(String path) {
        List<String> list = new ArrayList<String>();
        FTPFile[] flist = null;
        try {
            flist = ftpClient.listFiles(path);
            for (int i = 0; i < flist.length; i++) {
                if (!flist[i].isDirectory()) {
                    list.add(flist[i].getName());
                }
            }
        } catch (IOException e) {
            LOGGER.error("[FTP工具类]获取文件列表异常", e);
        }
        return list;
    }

    /**
     * 上传一个本地文件到FTP服务器
     *
     * @param remoteDir      要上传到服务器的目录 如：000/
     * @param remoteFileName 上传到服务器的文件名 如：000.txt
     * @param localFile      本地文件 如:c:/000.txt
     * @return
     */
    public boolean upload(String remoteDir, String remoteFileName,
                          File localFile) {
        InputStream stream = null;
        try {
            stream = new FileInputStream(localFile);
            // 设置本地模式
            LOGGER.info("ready to upload, now directory : "
                    + ftpClient.printWorkingDirectory());
            LOGGER.info("FTP default directory : "
                    + defaultWorkingDirectory);
            ftpClient.enterLocalPassiveMode();
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            if (defaultWorkingDirectory != null
                    && !"".equals(defaultWorkingDirectory)
                    && remoteDir.startsWith(defaultWorkingDirectory)) {
                remoteDir = ROOT + StringUtils.substringAfter(remoteDir, defaultWorkingDirectory);
            }
            boolean b = ftpClient.changeWorkingDirectory(remoteDir);
            LOGGER.info("changed directory "
                    + remoteDir + " [" + b + "], now directory : " + ftpClient.printWorkingDirectory());
            LOGGER.info("file name : " + localFile.getName()
                    + " is going to be uploaded as : " + remoteFileName);
            LOGGER.info("upload:" + remoteDir + remoteFileName);
            return ftpClient.storeFile(defaultWorkingDirectory + remoteDir + remoteFileName, stream);
        } catch (Exception e) {
            LOGGER.error("【FTP工具类】上传文件异常", e);
            return false;
        } finally {
            try {
                if (stream != null)
                    stream.close();
            } catch (IOException e) {
                LOGGER.error("【FTP工具类】上传文件异常", e);
            }
        }
    }

    /**
     * 从FTP服务器下载一个文件到本地目录，文件名一致
     *
     * @param remoteDir      服务端目录 如：000/
     * @param remoteFileName 要下载的文件名
     * @param localDir       本地目录 如：c:/000/
     * @return
     */
    public boolean download(String remoteDir, String remoteFileName,
                            String localDir) {

        File file = new File(localDir + remoteFileName);
        OutputStream out = null;
        // InputStream input = null;
        try {
            if (!file.exists())
                file.createNewFile();
            out = new FileOutputStream(file);
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            ftpClient.retrieveFile(remoteDir + remoteFileName, out);

            return true;
        } catch (Exception e) {
            LOGGER.error("[FTP工具类]下载文件异常", e);
            return false;
        } finally {
            try {
                // input.close();
                out.close();
            } catch (IOException e) {
                LOGGER.error("[FTP工具类]下载文件异常", e);
            }
        }
    }

    /**
     * 重命名远端FTP文件名
     *
     * @param fromFileName
     * @param toFileName
     * @return
     */
    public boolean renameFile(String fromFileName, String toFileName) {
        try {
            return ftpClient.rename(fromFileName, toFileName);
        } catch (IOException e) {
            LOGGER.error("[FTP工具类]重命名服务端文件异常", e);
            return false;
        }
    }

    public boolean changeToWorkDirectory(String path) {
        try {
            return ftpClient.changeWorkingDirectory(path);
        } catch (IOException e) {
            LOGGER.error("[FTP工具类]切换工作目录异常", e);
            return false;
        }
    }


    public boolean createDirectory(String dateStr) {
        try {
            return ftpClient.makeDirectory(dateStr);
        } catch (IOException e) {
            LOGGER.error("[FTP工具类]创建目录异常", e);
            return false;
        }
    }

    public boolean reCreateDirecroty(String remote)
            throws IOException {
        String directory = remote.substring(0, remote.lastIndexOf("/") + 1);
        if ((!directory.equalsIgnoreCase("/")) &&
                (!ftpClient.changeWorkingDirectory(directory))) {
            int start = 0;
            int end = 0;
            if (directory.startsWith("/"))
                start = 1;
            else {
                start = 0;
            }
            end = directory.indexOf("/", start);
            do {
                String subDirectory = new String(remote.substring(start, end));
                if (!ftpClient.changeWorkingDirectory(subDirectory)) {
                    if (ftpClient.makeDirectory(subDirectory)) {
                        ftpClient.changeWorkingDirectory(subDirectory);
                    } else {
                        LOGGER.error("创建目录失败");
                        return false;
                    }
                }

                start = end + 1;
                end = directory.indexOf("/", start);
            }

            while (end > start);
        }

        return true;
    }
}